package com.zrrd.gmall.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zrrd.gmall.common.result.Result;
import com.zrrd.gmall.common.result.ResultCodeEnum;
import com.zrrd.gmall.common.util.IpUtil;
import io.netty.util.internal.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.List;

@Component
public class AuthGlobaFilter implements GlobalFilter {
    @Autowired
    private RedisTemplate redisTemplate;

    //匹配路径的工具类
    private AntPathMatcher antPathMatcher = new AntPathMatcher();
    //需要登录校验的路径
    @Value("${authUrls.url}")
    private String authUrls;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //获取请求对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response =exchange.getResponse();
        //获取url
        String path = request.getURI().getPath();
        System.out.println("");
        //如果是内部的请求直接拦截 不允许访问
        if (antPathMatcher.match("/**/inner/**",path)){
            //给请求响应数据 不允许访问
            return  this.out(response,ResultCodeEnum.PERMISSION);
        }
        String userId = this.getUserId(request);
        //ip一致吗,不一致===被盗用
        if ("-1".equals(userId)){
            //给请求者响应一个数据
            return this.out(response,ResultCodeEnum.PERMISSION);
        }
        //用户登录认证
        if (antPathMatcher.match("/api/**/auth/**",path)){
            if (StringUtils.isEmpty(userId)){
                return this.out(response,ResultCodeEnum.LOGIN_AUTH);
            }
        }
        //访问是是否需要登录
        for (String authUrl : authUrls.split(",")) {
            //访问的是要登录的，而且你没登录
            if (path.indexOf(authUrl)!=-1 && StringUtils.isEmpty(userId)){
                //提示303重定向
                response.setStatusCode(HttpStatus.SEE_OTHER);
                //回去登录
                response.getHeaders().set(HttpHeaders.LOCATION,
                        "http://www.gmall.com/login.html?originUrl="+request.getURI());
                //完成重定向
                return response.setComplete();
            }
        }
        //获取临时用户Id
        String userTempId = this.getUserTempId(request);
        //临时id不为空 或者 当前登录用户id不为空
        if (!StringUtils.isEmpty(userId) || !StringUtils.isEmpty(userTempId)){
           //如果到此 说明登录了 ，将userId 继续传递
            if (!StringUtils.isEmpty(userId)) {
                request.mutate().header("userId", userId).build();
            }
            if (!StringUtils.isEmpty(userTempId)){
                request.mutate().header("userTempId",userTempId).build();
            }
            //响应
            return chain.filter(exchange.mutate().request(request).build());
        }
        //代表放行
        return chain.filter(exchange);
    }
    //判断有无用户信息的方法
    private String getUserId(ServerHttpRequest request){
        String token="";
        List<String> tokenlist = request.getHeaders().get("token");
        if (tokenlist!=null){
            //从请求头中获取token
            token = tokenlist.get(0);
        }else {
            MultiValueMap<String, HttpCookie> cookies = request.getCookies();
            HttpCookie cookie = cookies.getFirst("token");
            if (cookie!=null){
                token = URLDecoder.decode(cookie.getValue());
            }
        }
        //结束后 token中不一定有值
        if (!StringUtils.isEmpty(token)){
            //redis获取
            String userStr = (String) redisTemplate.opsForValue().get("user:login:" + token);

            JSONObject userJson = JSONObject.parseObject(userStr);
            String ip = userJson.getString("ip");
            String currentIp = IpUtil.getGatwayIpAddress(request);
            //ip对比
            if (ip.equals(currentIp)){
                //获取id 返回
                return userJson.getString("userId");
            }else {
                return "-1";
            }
        }
        return "";
    }


    //获取临时id
    private String getUserTempId(ServerHttpRequest request){
        String userTempId = "";
        List<String> list =request.getHeaders().get("userTempId");
        if (list != null){
            userTempId = list.get(0);
        }else {
            MultiValueMap<String, HttpCookie> cookies = request.getCookies();
            HttpCookie cookie = cookies.getFirst("userTempId");
            if (cookie!=null){
               userTempId= URLDecoder.decode(cookie.getValue());
            }
        }
        return userTempId;
    }


    //响应信息的方法（无权限）
    private Mono<Void> out(ServerHttpResponse response , ResultCodeEnum resultCodeEnum){
        //创建返回结果
        Result<Object> result = Result.build(null,resultCodeEnum);
        //将对象转json ，获取json字符
        byte[] bytes = JSONObject.toJSONString(result).getBytes(StandardCharsets.UTF_8);
        DataBuffer wrap = response.bufferFactory().wrap(bytes);
        response.getHeaders().add("Content-Type","application/json;charset=UTF-8");
        return response.writeWith(Mono.just(wrap));
    }
}
